understand the five most commonly-used data structures in R
be able to create and manipulate these data structures
be familiar with the ‘tibbles’ data structure
9.2 Reading
Before this tutorial you should access and review the following papers:
R. Rein and D. Memmert, “Big data and tactical analysis in elite soccer: Future challenges and opportunities for sports science,” SpringerPlus, vol. 5, no. 1, p. 1410, Dec. 2016.[1]
L. Corain, R. Arboretti, R. Ceccato, F. Ronchi, and L. Salmaso, “Testing and ranking on round-robin design for data sport analytics with application to basketball,” Statistical Modelling, vol. 19, no. 1, pp. 5–27, 2019. [2]
F. Lord, D. B. Pyne, M. Welvaert, and J. K. Mara, “Methods of performance analysis in team invasion sports: A systematic review,” Journal of Sports Sciences, vol. 38, no. 20, pp. 2338–2349, Oct. 2020.[3]
There are direct links to these papers via the library reading list.
9.3 Introduction
In R, data structures are the fundamental ways in which data is organized and stored for use in our analysis and modeling.
R has various types of data structures, each optimised for different kinds of tasks. In this tutorial we’ll identify the five most common data structures that you’re likely to use within sport data analytics, and explore how to create and manipulate data within these structures.
9.4 Type One: Matrices
A matrix is a two-dimensional data structure in R.
It’s used to store and organize data in rows and columns, similar to a spreadsheet. It’s important to note that, just like vectors, all elements within a matrix must be of the same data type.
9.4.1 Creating matrices
We use the ‘matrix()’ function to create a matrix by specifying the dataset, the number of rows, and the number of columns in the matrix. For example:
data <-c(1, 2, 3, 4, 5, 6) # create datamatrix_1 <-matrix(data, nrow =2, ncol =3) matrix_2 <-matrix(data, nrow =3, ncol =2)# print these to console windowprint(matrix_1)
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
print(matrix_2)
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
9.4.2 Accessing matrix elements
We use square brackets ‘[ ]’ with row and column indices to access elements in a matrix.
Use the ‘*’ operator to perform matrix multiplication (not element-wise):
multiplied_matrix <- A *t(B)print(multiplied_matrix)
[,1] [,2]
[1,] 5 18
[2,] 14 32
9.5 Type Two: Arrays
Like a matrix, an ‘array’ can also be used to store data in a structured manner.
While a matrix is a two-dimensional structure (with rows and columns), an array is multi-dimensional.
It is unlikely that you will need to deal with arrays, but it’s worth knowing that they are there if you need them!
There’s a good introduction to Arrays in R here. https://www.tutorialspoint.com/r/r_arrays.htm
9.6 Type Three: Lists
Lists are used to store and organize a collection of elements. Unlike vectors and matrices, lists can store elements of different data types and structures, such as numbers, characters, vectors, matrices, data frames, and even other lists.
9.6.1 Creating a list
You can use the list() function to create a list by combining elements:
You can apply functions to lists to perform different operations, such as calculating the length of the list or extracting specific elements from it:
list_length <-length(simple_list) # returns the list lengthfirst_two_elements <- simple_list[1:2] # returns the first two elements of the list
9.6.6 Converting lists
You can convert a list to other data structures using functions such as ‘unlist()’, ‘as.data.frame()’, or ‘as.matrix()’, as long as the list’s structure permits it:
Data frames are a core data structure in R, and are used to store and organize data in a tabular format with rows and columns.
Before the introduction of tibbles (see below), they were the most common data structure encountered while using R.
Data frames are similar to matrices, but can store columns of different data types, making them ideal for handling datasets with mixed data types. They closely resemble the way that data is stored in a spreadsheet application such as Excel, where you can have different types of data in different columns within your worksheet.
9.7.1 Creating data frames
You use the ‘data.frame()’ function to create a data frame by combining vectors or other data structures as columns:
names <-c("Scotland", "England", "Wales")ages <-c(25, 30, 22)heights <-c(165, 180, 172)data <-data.frame(Name = names, Age = ages, Height = heights) # this creates a dataframe called 'data'
9.7.2 Accessing elements in a data frame
You can use square brackets [ ], double square brackets [[ ]], or the dollar sign with row and column indices or names to access elements, rows, or columns in your data frame.
For example:
first_row <- data[1, ]age_column <- data$Age # note how we refer to a specific vector (variable) within the dataframethird_row_second_column <- data[3, "Age"]
9.7.3 Modifying data frames
You can add, update, or remove elements, rows, or columns by assigning values using indexing or names.
data$Name[1] <-"Alicia"# change an elementdata$Weight <-c(60, 85, 75) # add a new columndata[4, ] <-c("David", 23, 185, 80) # add a new rowdata$Weight <-NULL# Remove the 'weight' column
9.7.4 Data frame operations
You can also perform operations on elements, rows, or columns within a data frame using indexing or names to access them:
data$Age <-as.numeric(data$Age) # we need to convert data$Age to a numeric variable typeavg_age <-mean(data$Age) # we can then do some calculations on ittall_people <- data[data$Height >175, ]
9.7.5 Data frame functions
You can apply functions to data frames to perform various operations, such as calculating the dimensions, extracting specific elements, and more:
You can also use this approach to remove a variable from a data frame:
data_02 <-subset(data_01, select =-c(X)) # creates a new data frame without variable 'X'
9.8 Type Five: Tibbles
‘Tibbles’ are a recent introduction to R, as part of the tidyverse package. They are intended to make data manipulation more straightforward, and you will increasingly see them being used in preference to the older ‘data frame’ structure.
Tibbles offer several improvements over data frames, such as better printing in the console, the ability to handle column names with special characters or spaces, and automatic data type detection.
Tibbles are an integral part of the ‘tidyverse’ package and work well with other tidyverse functions and packages.
As with all additional packages, you need to install and load the tidyverse package before you can use tibbles:
install.packages("tidyverse") # only use if you've not already got tidyverse installedlibrary(tidyverse)
9.8.1 Creating tibbles
You can use the tibble() function to create a tibble, by combining vectors or other data structures as columns:
Why would you want to use tibbles rather than data frames? Well, there are a few reasons:
Tibbles have a refined print method that shows only the first 10 rows and all the columns that fit on screen, making them much easier to work with for large datasets.
Unlike data frames, tibbles do not simplify the results of subsetting operations into the lowest possible dimension; they always return another tibble. This means you won’t unexpectedly get a vector when you thought you were working with a data frame.
Tibbles allow column names that don’t meet R’s variable naming rules, like those that don’t start with a letter, or those that include spaces. This can be useful when working with datasets that have unusual column names.
Tibbles are more “lazy” and “surly” than data frames, in that they delay most operations (like filtering or sorting) until they’re explicitly asked to perform them, and they’re more stringent about data types. This can make tibbles a bit slower than data frames for some operations, but it also helps prevent some common data cleaning and manipulation errors.
If a single row is selected from a data frame using square brackets, a data frame returns a vector. Tibbles, however, always return a tibble, which provides a more consistent behavior.
You will find that tibbles can provide more robust, predictable, and user-friendly behaviour than traditional data frames, particularly when dealing with large or complex datasets.
9.8.3 Accessing tibble elements
Similar to data frames, use square brackets [], double square brackets [[]], or the dollar sign with row and column indices or names to access elements, rows, or columns in a tibble:
Add, update, or remove elements, rows, or columns by assigning values using indexing or names:
tb$Name[1] <-"Alicia"tb$Weight <-c(60, 85, 75) # Add a new columntb <-add_row(tb, Name ="David", Age =23, Height =185, Weight =80) # Add a new rowtb$Weight <-NULL# Remove the 'Weight' column
9.8.5 Tibble operations
Perform operations on elements, rows, or columns within a tibble using indexing or names to access them:
This introduction to tibbles has really just scratched the surface of this data structure. Hadley Wickham has provided an excellent and comprehensive coverage here.
9.9 Activity: Creating and manipulating various data structures
The following activity allows you to practise some of the techniques covered above. You may also have to do some research to find out how to complete some of the challenges.
Install and load necessary packages (e.g. tidyverse)
Create a dataframe of a hypothetical football team’s player statistics. Include PlayerName, GoalsScored, and Assists.
Print the dataframe to the console.
Convert the above dataframe to a tibble and print it.
Add a new player’s statistics to the dataframe and a new column for “GamesPlayed.”
Using dplyr, filter out players who’ve scored more than 5 goals.
Calculate a new column “GoalPerGame” and get the average goals scored by the team.
Arrange players by goals scored in descending order.
Create a new column called ‘Position’. For each player, provide a value that represents the position they play.
Finally, group players by position and get the total goals scored for each position.
9.10 Solutions
Install and load necessary packages.
Show the answer
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.3 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.4 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.0
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Create a dataframe of a hypothetical football team’s player statistics.
# A tibble: 3 × 2
Position TotalGoals
<chr> <dbl>
1 Defender 3
2 Forward 11
3 Midfielder 17
[1]
R. Rein and D. Memmert, “Big data and tactical analysis in elite soccer: Future challenges and opportunities for sports science,”SpringerPlus, vol. 5, no. 1, p. 1410, Dec. 2016, doi: 10.1186/s40064-016-3108-2.
[2]
L. Corain, R. Arboretti, R. Ceccato, F. Ronchi, and L. Salmaso, “Testing and ranking on round-robin design for data sport analytics with application to basketball,”Statistical Modelling, vol. 19, no. 1, pp. 5–27, 2019, doi: 10.1177/1471082x18808630.
[3]
F. Lord, D. B. Pyne, M. Welvaert, and J. K. Mara, “Methods of performance analysis in team invasion sports: A systematic review,”Journal of Sports Sciences, vol. 38, no. 20, pp. 2338–2349, Oct. 2020, doi: 10.1080/02640414.2020.1785185.